package view;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

import model.DebateFormat;
import model.Speaker;
import model.SpeakerRole;
import tools.ToStringWrapper;
import tools.Translator;

import com.google.inject.Inject;
import com.google.inject.Provider;
import com.jidesoft.swing.CheckBoxTree;
import com.jidesoft.swing.CheckBoxTreeSelectionModel;

public class SpeakerOptionsDialog extends WindowAdapter {

	private final Translator tr;
	private final Provider<MainWindow> mainWindowProvider;
	private final Set<DebateFormat> formats;
	private boolean isShown;
	private final Set<SpeakerRole> allRoles;
	private CheckBoxTreeSelectionModel selectionModel;
	private Speaker speaker;

	@Inject
	public SpeakerOptionsDialog(Translator tr,
			Provider<MainWindow> mainWindowProvider, Set<DebateFormat> formats,
			Set<SpeakerRole> allRoles) {
		this.tr = tr;
		this.mainWindowProvider = mainWindowProvider;
		this.formats = formats;
		this.allRoles = allRoles;

	}

	public void showDialogAndSetOptions(Speaker speaker) {
		if (isShown) {
			throw new IllegalStateException("Dialog is already opened");
		}
		this.speaker = speaker;
		
		final JDialog dlg = new JDialog(mainWindowProvider.get(), tr.tr("OPTIONS"),
				true);

		GridBagLayout gridBag = new GridBagLayout();
		GridBagConstraints constraints = new GridBagConstraints();
		dlg.setLayout(gridBag);

		DefaultMutableTreeNode root = new DefaultMutableTreeNode(
				new ToStringWrapper<Collection<SpeakerRole>>(allRoles, "root"));
		
		List<TreePath> selected = new ArrayList<>();
		for (DebateFormat format : formats) {
			// Add format, government and opposition nodes
			DefaultMutableTreeNode formatNode = new DefaultMutableTreeNode(
					new ToStringWrapper<Collection<SpeakerRole>>(format.getAllRoles(), tr.tr(format.getLabel())));
			DefaultMutableTreeNode govNode = new DefaultMutableTreeNode(
					new ToStringWrapper<Collection<SpeakerRole>>(format.getGovRoles(), tr.tr("GOVERNMENT")));
			DefaultMutableTreeNode opNode = new DefaultMutableTreeNode(
					new ToStringWrapper<Collection<SpeakerRole>>(format.getOpRoles(), tr.tr("GOVERNMENT")));

			for (SpeakerRole role : format.getGovRoles()) {
				DefaultMutableTreeNode node = new DefaultMutableTreeNode(
						new ToStringWrapper<Collection<SpeakerRole>>(Collections.singleton(role), tr.tr(role.getLabel())));
			
				govNode.add(node);
				if (speaker.getIncludedRoles().contains(role)) {
					selected.add(new TreePath(new Object[] {root, formatNode, govNode, node}));
				}
			}

			for (SpeakerRole role : format.getOpRoles()) {
				DefaultMutableTreeNode node = new DefaultMutableTreeNode(
						new ToStringWrapper<Collection<SpeakerRole>>(Collections.singleton(role), tr.tr(role.getLabel())));
			
				opNode.add(node);
				if (speaker.getIncludedRoles().contains(role)) {
					selected.add(new TreePath(new Object[] {root, formatNode, opNode, node}));
				}

			}

			formatNode.add(govNode);
			formatNode.add(opNode);

			for (SpeakerRole role : format.getOtherRoles()) {
				DefaultMutableTreeNode node = new DefaultMutableTreeNode(
						new ToStringWrapper<Collection<SpeakerRole>>(Collections.singleton(role), tr.tr(role.getLabel())));
			
				formatNode.add(node);
				if (speaker.getIncludedRoles().contains(role)) {
					selected.add(new TreePath(new Object[] {root, formatNode, node}));
				}

			}
			root.add(formatNode);
		}

		DefaultTreeModel treeModel = new DefaultTreeModel(root);

		CheckBoxTree cbTree = new CheckBoxTree(treeModel);
		cbTree.setRootVisible(false);
		cbTree.setShowsRootHandles(false);
		cbTree.setDigIn(true);
		cbTree.setBorder(BorderFactory.createTitledBorder(tr
				.tr("ALLOWED_ROLES")));
		this.selectionModel = cbTree.getCheckBoxTreeSelectionModel();
		selectionModel.setSelectionPaths(selected.toArray(new TreePath[] {}));
		
		for (int i = 0; i < cbTree.getRowCount(); i++) {
			cbTree.expandRow(i);
		}
		
		
		constraints.fill = GridBagConstraints.BOTH;
		constraints.gridy = 0;
		constraints.gridwidth = 1;

		gridBag.setConstraints(cbTree, constraints);
		dlg.add(cbTree);

		JButton closeButton = new JButton(tr.tr("OK"));
		constraints.gridy++;
		gridBag.setConstraints(closeButton, constraints);
		closeButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent arg0) {
				dlg.setVisible(false);
				windowClosing(null);
			}
		});
		
		dlg.add(closeButton);

		dlg.pack();
		dlg.setLocationByPlatform(true);
		dlg.addWindowListener(this);
		isShown = true;
		dlg.setVisible(true);

	}

	@Override
	public void windowClosing(java.awt.event.WindowEvent e) {
		// Collect selected roles and apply changes
		Set<SpeakerRole> includedRoles = new HashSet<>();
		for (TreePath p : selectionModel.getSelectionPaths()) {
			DefaultMutableTreeNode last = (DefaultMutableTreeNode) p.getLastPathComponent();
			@SuppressWarnings("unchecked")
			ToStringWrapper<Collection<SpeakerRole>> selected = 
					(ToStringWrapper<Collection<SpeakerRole>>) last.getUserObject();
			for (SpeakerRole role: selected.get()) {
				includedRoles.add(role);
			}
		}
		speaker.setIncludedRoles(includedRoles);
		isShown = false;
	};
}
